package crp.services.api.graphql;

import com.qwlabs.graphql.relay.Connection;
import com.qwlabs.graphql.relay.Relays;
import crp.core.course.app.CourseService;
import crp.core.course.domain.models.CourseEntity;
import crp.core.resource.app.ResourceService;
import crp.core.shared.SharedMessages;
import crp.services.api.graphql.models.CreateCourseResourceInput;
import crp.services.api.graphql.models.ResourcePayload;
import crp.services.api.graphql.models.UpdateResourceInput;
import org.eclipse.microprofile.graphql.DefaultValue;
import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Mutation;
import org.eclipse.microprofile.graphql.Query;

import javax.annotation.security.PermitAll;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

@GraphQLApi
@RequestScoped
@Transactional
public class ResourceGraphQLApi {
    private final CourseService courseService;
    private final ResourceService resourceService;

    @Inject
    public ResourceGraphQLApi(CourseService courseService,
                              ResourceService resourceService) {
        this.courseService = courseService;
        this.resourceService = resourceService;
    }

    @Query
    @PermitAll
    @NotNull
    public Connection<ResourcePayload> resources(
            @DefaultValue("0") String after,
            @DefaultValue("10") Integer first) {
        return Relays.of(resourceService.searcher().by(Relays.of(after, first)), ResourcePayload::of);
    }

    @Mutation
    @NotNull
    public Boolean publishResource(@NotBlank @Valid String id) {
        resourceService.editor().publish(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean batchPublishResource(@NotEmpty @Valid List<String> ids) {
        resourceService.editor().batchPublish(ids);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean unPublishResource(@NotBlank @Valid String id) {
        resourceService.editor().unPublish(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean publicizeResource(@NotBlank @Valid String id) {
        resourceService.editor().publicize(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean unPublicizeResource(@NotBlank @Valid String id) {
        resourceService.editor().unPublicize(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean enableResource(@NotBlank @Valid String id) {
        resourceService.editor().enable(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean disableResource(@NotBlank @Valid String id) {
        resourceService.editor().disable(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean deleteResource(@NotBlank @Valid String id) {
        resourceService.editor().delete(id);
        return true;
    }

    @Mutation
    @NotNull
    public Boolean updateResource(@Valid UpdateResourceInput input) {
        resourceService.editor().update(input.getId(), resource -> {
            resource.setAlias(input.getName());
        });
        return true;
    }

    @Mutation
    @NotNull
    public ResourcePayload createResource(@Valid CreateCourseResourceInput input) {
        CourseEntity course = courseService.searcher().findById(input.getCourseId())
                .orElseThrow(() -> SharedMessages.INSTANCE.entityNotFound("course", input.getCourseId()));
        return ResourcePayload.of(resourceService.editor().create(input.of(course)));
    }

    @Mutation
    @NotNull
    public Boolean syncResource() {
        resourceService.sync();
        return true;
    }
}
